package com.acme.bankapp.domain.bank;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.acme.bankapp.BankApplication;
import com.acme.bankapp.domain.bank.client.AbstractClientListener;
import com.acme.bankapp.domain.bank.client.Client;
import com.acme.bankapp.domain.bank.client.ClientExistsException;
import com.acme.bankapp.domain.bank.client.ClientRegistrationListener;

/**
 * @author Andrey Alekov
 * Bank class.
 */
public class Bank implements Serializable{
	private static final long serialVersionUID = -1920315668066086947L;
	final static Logger logger = LoggerFactory.getLogger(BankApplication.class);
	private String bankName;
	private List<Client> clients = new ArrayList<Client>();
	private List<AbstractClientListener> listeners = 
			new ArrayList<AbstractClientListener>();
	
	/**
	 * Constructor.
	 * @param bankName
	 */
	public Bank(String bankName) {
		this.setBankName(bankName);
		class PrintClientListener extends AbstractClientListener {
			@Override
			public void onClientAdded(Client client) {
				logger.info(client.toString());
			}
		}
		final class EmailNotificationListener extends AbstractClientListener {
			@Override
			public void onClientAdded(Client client) {
				logger.info("Notification email to " + client.toString()
						+ " to be sent.");
			}
		}
		this.listeners.add(new PrintClientListener());
		this.listeners.add(new EmailNotificationListener());
	}
	
	/**
	 * Constructor with specific listeners.
	 * @param bankName to set
	 * @param listeners list of custom listeners.
	 */
	public Bank(String bankName, List<AbstractClientListener> listeners) {
		this.setBankName(bankName);
		this.listeners = listeners;
	}
	
	/**
	 * Get list of clients
	 * @return List<Client> 
	 */
	public List<Client> getClients(){
		return this.clients;
	}
	
	/**
	 * Get bank name.
	 * @return String bank name
	 */
	public String getBankName() {
		return bankName;
	}

	/**
	 * Set new bank name.
	 * @param bankName to set
	 */
	public void setBankName(String bankName) {
		this.bankName = bankName;
	}

	/**
	 * Method prints maximum amount to withdraw for each client.
	 * @param client to add in bank
	 * @throws ClientExistsException when client are exist in bank
	 */
	public void addClient(Client client) throws ClientExistsException{
		for (Client localClient: this.clients) {
			if (localClient.getName().equals(client.getName())){
				throw new ClientExistsException(client.toString() 
						+ "are exist.");
			}
		}
		this.clients.add(client);
		for (ClientRegistrationListener listener : this.listeners) {
			listener.onClientAdded(client);
		}
	}

	/**
	 * Method prints maximum amount to withdraw for each client.
	 */
	public void printMaximumAmountToWithdraw() {
		for (Client client : clients) {
			for (Account account : client.getAccounts()){
				logger.info("Client: " + client.getName() + "\t" 
							+ "Client Account: " + account.getAccountId() + "\t"
							+ "Account amount: " + account.maximumAmountToWithdraw());
			}
		}
	}
}

